<?php

class Materials_Model_Comment extends Workset_Model_Object_Abstract implements Workset_Model_Object_TreeNode_Interface
{

    const TYPE = 'materials_comment';

    protected $_objectType = self::TYPE;

    protected $_comments = array();

    /**
     * Возвращает объект Materials_Model_Comment по primary key
     *
     * @static
     * @param  mixed $identity
     * @return Materials_Model_Comment
     *
     */
	static function getInstance($identity) {
		$storage = self::getDefaultStorage(self::TYPE);
		return self::getFromStorage($storage, $identity);
	}

    /**
     * Создает новый объект Materials_Model_Comment с полями $data
     *
     * @static
     * @param  array $data
     * @return Materials_Model_Comment
     *
     */
	static function create($data) {
		$storage = self::getDefaultStorage(self::TYPE);
		return $storage->create($data);
	}

    /**
     * Возвращает список комментариев
     *
     * @static
     * @param  mixed $where
     * @param  mixed $order
     * @param  int $limit
     * @param  int $offset
     * @return Workset_Model_Object_Iterator
     *
     */
    static function getAll($where = null, $order = null, $limit = null, $offset = null, $offsetByPage = false) {
        $storage = self::getDefaultStorage(self::TYPE);
        return $storage->getAll($where, $order, $limit, $offset, $offsetByPage);
    }

    /**
     * Возвращает список комментариев к самым популярным материалам.
     * 
     * @static
     * @param  $order
     * @param  $limit
     * @return Workset_Model_Object_Iterator
     */
    static function getPopularByMaterial($where = null, $order = null, $limit = null, $offset = null, $offsetByPage = false) {
        $storage = self::getDefaultStorage(self::TYPE);
        return $storage->getPopularByMaterial($where, $order, $limit, $offset, $offsetByPage);
    }

    /**
     * Возвращает последний комментарий.
     * Если $where не указан, то возвращается комментарий с самым большим ID
     * 
     * @static
     * @param  $where
     * @return Materials_Model_Comment
     */
    static function getLastComment($where = null) {
        $storage = self::getDefaultStorage(self::TYPE);
        return $storage->getLastComment($where);
    }

    /**
     * Инициализация объекта
     *
     * @return void
     */
	public function init() {
		$this->attach(new Workset_Model_Observer_TreeNodeUpdater('answers'));
		$this->attach(new Materials_Model_Comment_Observer_MaterialCommentsUpdater());
	}

    /**
     * Устанавливает материал
     *
     * @param  int|Materials_Model_Material $material
     * @return Materials_Model_Comment
     */
    public function setMaterial($material) {
        if ($this->getId() > 0) {
            throw new Workset_Model_Exception('Material already exists');
        }

        if (!$material instanceof Materials_Model_Material) {
			$material = Materials_Model_Material::getInstance($material);
		}

        if ($material) {
            $this['material_id'] = $material->getId();
        } else {
            throw new Workset_Model_Exception('Material is not exists');
        }

        return $this;
    }

	/**
	 * Возвращает материал, к которому принадлежит комментарий
	 *
	 * @return Catalogue_Model_Object
	 */
    public function getMaterial() {
        return Materials_Model_Material::getInstance($this->getMaterialId());
    }

	/**
	 * Возвращает ID материала, к которому принадлежит комментарий
	 *
	 * @return int
	 */
    public function getMaterialId() {
        return (int)$this['material_id'];
    }

	/**
	 * Устанавливает ID родительского коммметария
	 *
	 * @param  $parentId
	 * @return Materials_Model_Comment
	 */
	public function setParentId($parentId) {
		if ($parentId > 0) {
            $this['parent_id'] = (int)$parentId;
        }
        return $this;
	}

    /**
     * Устанавлмвает родительский комментарий
     *
     * @param  $comment
     * @return Materials_Model_Comment
     */
    public function setParent(Workset_Model_Object_TreeNode_Interface $parent) {
        if ($parent instanceof Materials_Model_Comment) {
			$this->setParentId($parent->getId());
		}
        return $this;
    }

	/**
	 * Возвращает родительский комментарий
	 *
	 * @return Materials_Model_Comment
	 */
    public function getParent() {
        if ($this['parent_id'] > 0) {
            return Materials_Model_Comment::getInstance($this['parent_id']);
        } 
    }

    /**
     * Возвращает ID родительского комментария
     *
     * @return int
     */
    public function getParentId() {
        return $this['parent_id'] > 0 ? (int)$this['parent_id'] : null;
    }

    /**
     * Проверяет, есть ли родительский комментарий
     *
     * @return bool
     */
    public function hasParent() {
        return $this['parent_id'] > 0;
    }

    /**
     * Возвращает содержимое комментария
     *
     * @return string
     */
    public function getMessage() {
        return $this['message'];
    }

    /**
     * Возвращает уровень вложенности комментария.
     * У корневых комментариев уровень вложенности - 0.
     *
     * @return int
     */
    public function getDepth() {
        return (int)$this['depth'];
    }

    /**
     * Возвращает число ответов на комментарий
     *
     * @return int
     */
    public function getAnswersCount() {
        $count = (int)$this['answers'];

        if ($this->hasAnswers()) {
            $answers = $this->getAnswers();

            foreach ($answers as $answer) {
               if ($answer->hasAnswers()) {
                    $count += $answer->getAnswersCount();
               }
            }
        }

        return $count;
    }

    /**
     * Возвращает список ответов на комментарий ввиде объекта Workset_Model_Object_Iterator
     *
     * @param  $filter
     * @param  $order
     * @param  $limit
     * @param  $offset
     * @return Workset_Model_Object_Iterator
     */
    public function getAnswers($filter = null, $order = null, $limit = null, $offset = null) {
        if (empty($filter)) {
            $filter = array('parent_id = ?' => $this->getId());
        } else {
            $filter = (array)$filter;
            $filter['parent_id = ?'] = $this->getId();
        }

        return Materials_Model_Comment::getAll($filter, $order, $limit, $offset);
    }

    /**
     * Проверяет, есть ли ответы на комментарий
     *
     * @return bool
     */
    public function hasAnswers() {
        return $this['answers'] > 0;
    }

	/**
	 * @deprecated
	 * @return Materials_Model_Comment
	 */
    public function incrementAnswersCount() {
        $this['answers'] += 1;
        return $this;
    }

	/**
	 * @deprecated
	 * @return Materials_Model_Comment
	 */	
    public function decrementAnswersCount() {
        $this['answers'] -= 1;
        return $this;
    }

    /**
     * Добавляет ответ на комментарий
     *
     * @param Materials_Model_Comment $comment
     * @return Materials_Model_Comment
     */
    public function addComment(Materials_Model_Comment $comment) {
        $comment->setParent($this)
                ->setMaterial($this->getMaterial());

        $this->_comments[] = $comment;
        $this->_update = true;

        return $this;
    }

    /**
     * Сохраняет комментарий в хранилище данных
     *
     * @return int
     */
    public function save() {

		$this['depth'] = $this->_calcDepth();

        if ($this->_comments) {
            foreach ($this->_comments as $comment) {
               $comment->save();
            }
        }

        return parent::save();
    }

	/**
     * @return int
     *
     * Вычисляет уровень вложенности комментария
     */
    protected function _calcDepth() {
        if (!$this->hasParent()) {
            return 0;
        } else {
            return $this->getParent()->getDepth() + 1;
        }
    }
    
}